package com.wan.util.cglib;

import cn.hutool.core.bean.BeanUtil;
import net.sf.cglib.reflect.FastMethod;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 属性访问器，必须带get和set方法
 */
public class FastField {

    private final Field field;
    private final FastMethod getter;
    private final FastMethod setter;
    private final Object[] nullArgs = new Object[0];

    public FastField(Field field){
        this.field = field;
        Class<?> declaringClass = field.getDeclaringClass();
        PropertyDescriptor propertyDescriptor = BeanUtil.getPropertyDescriptor(declaringClass, field.getName());
        if(propertyDescriptor == null){
            throw new RuntimeException("要访问的属性必须要有get和set方法！class:" +
                    declaringClass.getCanonicalName() + ",field:" + field.getName());
        }
        Method readMethod = propertyDescriptor.getReadMethod();
        Method writeMethod = propertyDescriptor.getWriteMethod();
        if(readMethod == null || writeMethod == null){
            throw new RuntimeException("要访问的属性必须要有get和set方法！class:" +
                    declaringClass.getCanonicalName() + ",field:" + field.getName());
        }
        getter = FastClassUtil.getFastMethod(readMethod);
        setter = FastClassUtil.getFastMethod(writeMethod);
    }

    public Field getField() {
        return field;
    }

    public FastMethod getGetter() {
        return getter;
    }

    public FastMethod getSetter() {
        return setter;
    }

    public String getName(){
        return field.getName();
    }

    public Class<?> getType(){
        return field.getType();
    }

    public Class<?> getBeanClass(){
        return field.getDeclaringClass();
    }

    public Object get(Object obj) throws InvocationTargetException {
        return this.getter.invoke(obj,nullArgs);
    }

    public void set(Object obj,Object value) throws InvocationTargetException {
        this.setter.invoke(obj,new Object[]{value});
    }
}
